4. Язык ассемблера A64
=Язык ассемблера A64= Базовые структуры The letter W is shorthand for a 32-bit word, and X for a 64-bit extended word. The letter X (extended) is used rather than D (double), since D conflicts with its use for floating point and SIMD “double-precision” registers and the T32 load/store “double-register” instructions (e.g. LDRD). An A64 assembler will recognise both upper and lower-case variants of instruction mnemonics and register names, but not mixed case. An A64 disassembler may output either upper or lower-case mnemonics and register names. The case of program and data labels is significant. The fundamental statement format and operand order follows that used by AArch32 UAL assemblers and disassemblers, i.e. a single statement per source line, consisting of one or more optional program labels, followed by an instruction mnemonic, then a destination register and one or more source operands separated by commas. {label:*} {opcode {dest{, source1{, source2{, source3}}}}} Буква W используется как сокращение для 32-х битного слова, а X -для 64-х битного расширенного слова. Использование X (extended) предпочтительнее D (double), т.к. D совпадает с обозначением числа с плавающей точкой в терминах SIMD (регистр двойной точности) и в терминах T32 (операции load/store для двойного регистра, например LDRD). В ассемблере A64 допустимо написание инструкций и имен регистров как в верхнем регистре, так и в нижнем, но запрещено смешивать оба варианта. Вывод дизассемблер A64 может так же содержать текст с обоими вариантами написания. Меток (labels), ссылающихся на код и данные чуствительны к регистру. Базовые концепции формата и очередность операнд те же, что и в ассемблере UAL AArch32 и соответствущем дизассемблере. Это означает: одно выражение на одну строку исходного кода, наличие или отсутствие одной или нескольких меток перед именем инструкции, а так же разделение запятыми регистров-приемников или входных операндов, если их указано несколько. {label:*} {opcode {dest{, source1{, source2{, source3}}}}} This dest/source ordering is reversed for store instructions, in common with AArch32 UAL. The A64 assembly language does not require the ‘#’ symbol to introduce immediate values, though an assembler must allow it. An A64 disassembler shall always output a ‘#’ before an immediate value for readability. Where a user-defined symbol or label is identical to a pre-defined register name (e.g. “X0”) then if it is used in a context where its interpretation is ambiguous – for example in an operand position that would accept either a register name or an immediate expression – then an assembler must interpret it as the register name. A symbol may be disambiguated by using it within an expression context, i.e. by placing it within parentheses and/or prefixing it with an explicit ‘#’ symbol. In the examples below the sequence “//” is used as a comment leader and ARMv8 assemblers are encouraged to accept this syntax, though they may also support their legacy A32 and T32 comment syntax. В случае с операциями store, операнды dest и source меняются местами, аналогично UAL AArch32. Язык ассемблера A64 не требует наличия символа '#' перед непосредственными значениями, однако ассемблер позволяет такой формат записи. Дизассемблер A64 должен всегда включать в вывод '#', чтобы улучшить читаемость. Когда символ (переменная) или метка названы точно так же, как регистр (например “X0”) и используется в конструкции не позволяющей однозначно ее интерпретировать (например в качестве операнда), то данное имя рассматривается как имя регистра. Символ может быть интерпретирован неоднозначно, если он использован в контексте выражения, т.е. находится внутри круглых скобок и/или пред ним явно указан ‘#’. Далее в примерах кода присутствуют комментарии. Они начинаются с “//”, что является допустимым для ассемблера ARMv8. Допустим так же формат комментариев унаследованный от A32 и T32. Мнемоники(имена) инструкций An A64 instruction form can be identified by the following combination of attributes: • The operation name (e.g. ADD) which indicates the instruction semantics. • The operand container, usually the register type. An instruction writes to the whole container, but if it is not the largest in its class, then the remainder of the largest container in the class is set to ZERO. • The operand data subtype, where some operand(s) are a different size from the primary container. • The final source operand type, which may be a register or an immediate value. Формат инструкций A64 может быть описан комбинацией следующих атрибутов: *Имя операции (например ADD), определяющее остальную семантику инструкции *Контейнер операндов, часто это регистр. Инструкция модифицирует контейнер целиком, за *исключением случаев, когда инструкция относится к классу оперирующих контейнерами меньшего размера. В этом случае, оставшаяся часть контейнера заполняется нулями. *Подтип данных операнда, позволяющий операндам иметь размер, отличающийся от главного контейнера. *Тип последнего входного операнда. Это может быть регистр или непосредственное значение. The container is one of: Integer Class W 32-bit integer X 64-bit integer SIMD Scalar & Floating Point Class B 8-bit scalar H 16-bit scalar & half-precision float S 32-bit scalar & single-precision float D 64-bit scalar & double-precision float Q 128-bit scalar Типы значений в контейнере: Целочисленные типы W''' - 32-х битные целые '''X - 64-х битные целые Скалярные значения для SIMD и типы с плавающей точкой B''' - 8-и битное скалярное значение '''H - 16-и битное скалярное значение и число с плавающей точкой (половина одинарной точности) S''' - 32-х битное скалярное значение и число с плавающей точкой (одинарная точность) '''D - 64-х битное скалярное значение и число с плавающей точкой (двойная точность) Q''' - 128-и битное скалярное значение '''The subtype is one of: Load-Store / Sign-Zero Extend B byte SB signed byte H halfword SH signed halfword W word SW signed word Register Width Changes H High (dst gets top half) N Narrow (dst < src) L Long (dst > src) W Wide (dst src1, src1 > src2) etc Список подтипов: Load-Store / Дополненный нулями или знаком B''' - байт '''SB - байт со знаком H''' - полуслово '''SH - полуслово со знаком W''' - слово '''SW - слово со знаком Изменение Длинны регистров H (High) - Старшие биты (dst занимает старшую половину) N (Narrow - Сужение (dst < src) L (Long) - Удлинение (dst > src) W (Wide) - По ширине (dst src1, src1 > src2) и т.д. These attributes are combined in the assembly language notation to identify the specific instruction form. In order to retain a close look and feel to the existing ARM assembly language, the following format has been adopted: {} ''' '''In other words the operation name and subtype are described by the instruction mnemonic, and the container size' by the operand name(s). Where subtype is omitted, it is inherited from container. In this way an assembler programmer can write an instruction without having to remember a multitude of new mnemonics; and the reader of a disassembly listing can straightforwardly read an instruction and see at a glance the type and size of each operand. The implication of this is that the A64 assembly language overloads instruction mnemonics, and distinguishes between the different forms of an instruction based on the operand register names. For example the ADD instructions below all have different opcodes, but the programmer only has to remember one mnemonic and the assembler automatically chooses the correct opcode based on the operands – with the disassembler doing the reverse. Данные атрибуты комбинируются в нотации языка ассемблера для описания конкретной формы инструкции. Следующий формат был унаследован с целью сохранения привычного языка ассемблера ARM: {} Другими словами, название операции и подтип включаются в мнемонику инструкции, а размер контейнера в имена операнд. Если подтип не указывается, то он наследуется от контейнера. Это избавляет программиста от необходимости помнить множество новых мнемоник и делает вывод дизассемблера более понятным в плане типа и размера каждого операнда. При таком подходе, ассемблер A64 использует внутренние механизмы переопределения мнемоник инструкций и ориентируется в разных формах инструкций по именам регистров. Ниже приведён пример инструкции ADD превращающейся в разные опкоды, хотя программист применил одну и туже мненмонику. Ассемблер принял решение по опкодам. Дизасемблер выполнит действия в обратном порядке. ADD W0, W1, W2 // add 32-bit register ADD X0, X1, X2 // add 64-bit register ADD X0, X1, X2, W2, SXTW //add 64-bit extending register ADD X0, X1, #42 // add 64-bit immediate ADD W0, W1, W2 // сложить 32-х битные регистры ADD X0, X1, X2 // сложить 64-х битные регистры ADD X0, X1, X2, W2, SXTW // сложение с применение расширенного 64-х битного регистра ADD X0, X1, #42 // прибавить 64-х битное непосредственное значение Коды условий In AArch32 assembly language conditionally executed instructions are represented by directly appending the condition to the mnemonic, without a delimiter. This leads to some ambiguity which can make assembler code difficult to parse: for example ADCS, BICS, LSLS and TEQ look at first glance like conditional instructions. The A64 ISA has far fewer instructions which set or test condition codes. Those that do will be identified as follows: 1. Instructions which set the condition flags are notionally different instructions, and will continue to be identified by appending an ‘S’ to the base mnemonic, e.g. ADDS. 2. Instructions which are truly conditionally executed (i.e. when the condition is false they have no effect on the architectural state, aside from advancing the program counter) have the condition appended to the instruction with a '.' delimiter. For example B.EQ. 3. If there is more than one instruction extension, then the conditional extension is always last. 4. Instructions which are unconditionally executed, but use the condition flags as a source operand, will specify the condition to test in their final operand position, e.g. CSEL Wd,Wm,Wn,NE To aid portability an A64 assembler may also provide the old UAL conditional mnemonics, so long as they have direct equivalents in the A64 ISA. However, the UAL mnemonics will not be generated by an A64 disassembler – their use is deprecated in 64-bit assembler code, and may cause a warning or error if backward compatibility is not explicitly requested by the programmer. В языке ассемблера AArch32, условного выполнения инструкции можно добиться, дописав условия к мнемонике команд без каких либо разделителей. Это приводит, в ряде случаев, к двусмысленности ассемблерного кода и затрузняет чтение. Например ADCS, BICS, LSLS и TEQ на первый взгляд могу показаться условными инструкциями. Набор A64 ISA содержит гораздо меньше инструкций, способных устанавливать или проверять коды условий. К это категории будут относится только следующие команды: #Инструкции, устанавливающие флаги условий теперь можно четко отличить от всех остальных. Их мнемоники дополняются символом "S". Например ADDS. #Инструкции, которые по-настоящему можно считать условными (т.е. если условие ложно, оно ни как не изменят состояние аппаратуры, за исключением увеличения программного счетчика, перешедшего на следующую инструкцию). Условие добавляется в конец команды. При этом разделителем служит символ "." - точка. Например B.EQ. #Если при формировании инструкции использовалось несколько расширений, то расширение, отвечающее за условие должно указываться последним. #Инструкции, выполняющиеся безусловно, но использующие флаги условия, как входные операнды, должны задать проверку условий в позиции последнего операнда. Например CSEL Wd,Wm,Wn,NE. Чтобы облегчить портирование, ассемблер A64 поддерживает старые мнемоники условий, принятые в UAL, хотя им соответствуют прямые аналоги из A64 ISA. Однако, дизасемблер A64 не генерирует старые мнемоники. Такой способ считается устаревшим (deprecated) в 64-х битном ассемблерном коде и может вызвать ошибки, если программист не проконтролирует использованные обратной совместимости. The full list of condition codes is as follows: Полный список кодов условий выглядит следующим образом: (1) The condition code NV exists only to provide a valid disassembly of the ‘1111b’ encoding, and otherwise behaves identically to AL. (1) Код условия NV существует только для того чтобы избежать ошибок при дизассемблировании кода ‘1111b’. В остальном его поведение аналогично AL. Имена регистров Регистры общего назначения (целочисленные) The thirty one general purpose registers in the main integer register bank are named R0 to R30, with special register number 31 having different names, depending on the context in which it is used. However, when the registers are used in a specific instruction form, they must be further qualified to indicate the operand data size (32 or 64 bits) – and hence the instruction’s data size. The qualified names for the general purpose registers are as follows, where n is the register number 0 to 30: Where register number 31 represents read zero or discard result (aka the “zero register”): Where register number 31 represents the stack pointer: Тридцать один регистр общего назначения в главном регистровом банке названы R0..R30. Специальный регистр с номером 31 имеет несколько имен, в зависимости от контекста использования. Тем не менее, в случаях, когда регистры необходимо использовать в конкретной форме инструкции, необходимо уточнять размер операнда (32 или 64 бита), т.е. размер данных которые передаются на вход инструкции. Уточненное имя для регистров общего назначения выглядят следующем образом (где 'n' - номер регистра от 0 до 30): Если регистр с номером 31 используется для получения нулего значения или отправки "в никуда" (так называемый "нулевой регистр"): Если регистр с номером 31 используется как указатель стека: In more detail: The names Xn and Wn refer to the same architectural register. There is no register named W31 or X31. For instruction operands where register 31 in interpreted as the 64-bit stack pointer, it is represented by the name SP. For operands which do not interpret register 31 as the 64-bit stack pointer this name shall cause an assembler error. The name WSP represents register 31 as the stack pointer in a 32-bit context. It is provided only to allow a valid disassembly, and should not be seen in correctly behaving 64-bit code. For instruction operands which interpret register 31 as the zero register, it is represented by the name XZR in 64-bit contexts, and WZR in 32-bit contexts. In operand positions which do not interpret register 31 as the zero register these names shall cause an assembler error. Where a mnemonic is overloaded (i.e. can generate different instruction encodings depending on the data size), then an assembler shall determine the precise form of the instruction from the size of the first register operand. Usually the other operand registers should match the size of the first operand, but in some cases a register may have a different size (e.g. an address base register is always 64 bits), and a source register may be smaller than the destination if it contains a word, halfword or byte that is being widened by the instruction to 64 bits. The architecture does not define a special name for register 30 that reflects its special role as the link register on procedure calls. Such software names may be defined as part of the Procedure Calling Standard. Детальное описание: *Имена Xn и Wn соответствуют одному и тому же аппаратному регистру. *Регистров с именами W31 и X31 не существует. *Если 31-й регистр используется в позиции операнда инструкции как 64-х битная позиция в стеке, то для него используется имя SP. Для операндов, не способных интерпретировать 31-й регистр как 64-х битную позицию в стеке, данное имя вызовет ошибку ассемблера. *Имя WSP интерпретирует 31-й регистр как позицию в стеке в 32-х битном контексте. Данное имя введено только для правильного дизассамблирования и не должно встречаться в корректном 64-х битном коде. *Для операндов инструкций, которые интерпретируют 31-й регистр как нулевой, ему соответствует имя XZR в 64-х битном контексте и WZR в 32-х битном. Для операндов, не способных интерпретировать 31-й регистр как нулевой, данное имя вызовет ошибку ассемблера. *В случаях, когда мнемоника переопределяется (т.е. может генерировать различные коды инструкций в зависимости от разрядности данных) ассемблер должен руководствоваться размером первого регистра-операнда, предусмотренного формой инструкции. Размер других регистров-операнд должен совпадать с размером первого, но, в некоторых случаях, размер регистров может отличатся (например, размер регистра с базовым адресом всегда равен 64 битам) и регистр-источник может быть меньше регистра-назначения и содержать слово, полуслово или байт, которые будут расширены инструкцией до 64-х бит. *На аппаратном уровне не существует специального имени для 30-го регистра, выполняющего роль регистра-связки при вызове процедур. Имя может быть присвоено на программном уровне, как часть стандарта "Вызов процедуры" (Procedure Calling) Регистры для работы с плавающей точкой(FP) и SIMD-регистры The thirty two registers in the FP/SIMD register bank named V0 to V31 are used to hold floating point operands for the scalar floating point instructions, and both scalar and vector operands for the Advanced SIMD instructions. As with the general purpose integer registers, when they are used in a specific instruction form the names must be further qualified to indicate the data shape (i.e. the data element size and number of elements or lanes) held within them. Note however that the data type, i.e. the interpretation of the bits within each register or vector element integer (signed, unsigned or irrelevant), floating point, polynomial or cryptographic hash – is not described by the register name, but by the instruction mnemonics which operate on them. For more details see the Advanced SIMD description in §5.8. Тридцать два регистра в FP/SIMD регистровом банке называются V0..V31 и предназначены для хранения следующих видов операнд: операнды с плавающей точкой для скалярных FP-инструкций, а также скалярные операнды и операнды векторы для Расширенного SIMD (Advanced SIMD). Так же как и целочисленные регистры общего назначения, используемые в конкретных формах инструкции, данные регистры должны иметь имена, дополненные информацией о форме данных (data shape) внутри них (например размер элемента данных или количество элементов в рядах). Однако, мнемоники инструкций, а не имена регистров, должны определять типы данных (data type), т.е. интерпретацию бит в конкретных регистрах или элементов векторов: целое со знаком, без знака, не чувствительное к знаку (irrelevant), число с плавающей точкой, многочлен или криптографический хэш. Подробнее в гл.5.8. Скалярные SIMD-регистры In Advanced SIMD and floating point instructions which operate on scalar data the FP/SIMD registers behave similarly to the main general-purpose integer registers, i.e. only the lower bits are accessed, with the unused high bits ignored on a read and set to zero on a write. The qualified names for scalar FP/SIMD names indicate the number of significant bits as follows, where ‘n’ is a register number 0 to 31: В расширенном SIMD (Advanced SIMD) и FP-инструкциях, оперирующих скалярными данными, FP/SIMD регистры интерпретируются точно так же как целочисленные регистры общего назначения, т.е. доступны только младшие биты, а старшие биты игнорируются при чтении и обнуляются при записи. Дополненные имена FP/SIMD-регистров отражают количество значащих бит следующим образом (n - номер регистра от 0 до 31): 4.4.2.2 SIMD vector register When a register holds multiple data elements on which arithmetic will be performed in a parallel, SIMD fashion, then a qualifier describes the vector shape: i.e. the element size, and the number of elements or “lanes”. Where “bits lanes” does not equal 128, the upper 64 bits of the register are ignored when read and set to zero on a write. The fully qualified SIMD vector register names are as follows, where ‘n’ is the register number 0 to 31: Векторные SIMD-регистры Если регистр содержит несколько элементов и арифметические действия над ними будут выполнятся параллельно (в стиле SIMD), то дополнение к имени должно описать форму вектора: размер элемента, количество элементов или рядов. Причем "ряд бит" - это не 128 бит, старшие 64 бит регистра игнорируются при чтении и обнуляются при записи. Все варианты дополненных имен векторных SIMD-регистров (n - номер регистра от 0 до 31): 4.4.2.3 SIMD vector element Where a single element trom a SIMD vector register is used as a scalar operand, this is indicated by appending a constant, zero-based "element index" to the vector register name, inside square brackets. The number of lanes is not represented, since it is not encoded, and may only be interred from the index value. However an assembler shall accept a fully qualified SIMD vector register name as in §4.4.2.2, so long as the number of lanes is greater than the index value. For example the following forms will both be accepted by an assembler as the name for the 32-bit element in bits <63:32> of SIMD register 9: Note that the vector register element name Vn.S0 is not equivalent to the scalar register name Sn. Although they represent the same bits in the register, they select different instruction encoding forms, i.e. vector element vs scalar form. Элементы SIMD-вектора Если отдельный элемент векторного SIMD-регистра будет использоваться как скалярный операнд, то к имени векторного регистра добавляется индекс элемента в квадратных скобках, являющийся его порядковым номером, начиная с нуля. Номера рядов не указываются, т.к. они не кодируются при хранении и получаются вычилением из индекса. Тем не менее, ассемблер должен принимать и полную форму имени векторных SIMD-регистров (см гл.4.4.2.2), пока номер ряда больше значения индекса. Например следующие формы приемлемы в качестве имени 32-х битного элемента (с 63 по 32 бит) помещенного в 64-х разрядный SIMD - регистр с номером 9. V9.S1 стандарт для дизассемблера V9.2S1 опциональный номер для ряда V9.4S1 опциональный номер для ряда Обратите внимание: имя элемента векторного регистра Vn.S0 не эквивалентно имени скалярного регистра Sn. Хотя они представляют одну и туже последовательность бит, они относятся к разным кодам инструкций - элемент вектора и скалярное значение. 4.4.2.4 SIMD vector register list Where an instruction operates on a “list” of vector registers – for example vector load-store and table lookup – the registers are specified as a list within curly braces. This list consists of either a sequence of registers separated by commas, or a register range separated by a hyphen. The registers must be numbered in increasing order (modulo 32), in increments of one or two. The hyphenated form is preferred for disassembly if there are more than two registers in the list, and the register numbers are monotonically increasing in increments of one. The following are equivalent representations of a set of four registers V4 to V7, each holding four lanes of 32-bit elements: Список векторных SIMD-регистров Если инструкция обрабатывает "список" векторных регистров, то либо указывается последовательность регистров, разделенных запятыми, либо, с помощью дефиса, задается диапазон. Пример: векторные load/store и поиск по таблице (table lookup). Регистры должны быть пронумерованы в сторону увеличения (вплоть до 32 (modulo 32)) с единичным или двойным шагом. Диапазон, указанный через дефис предпочтительнее для дизасемблера, если он обнаруживает список из более чем двух регистров и их номера равномерно увеличиваются с единичным шагом. Эквивалентные представления множества из четырех регистров от V4 до v7, каждый из которых содержит четыре ряда 32-х битных элементов, выглядят следующим образом: {V4.4S – V7.4S} стандарт для дизассемблера {V4.4S, V5.4S, V6.4S, V7.4S} альтернативное представление 4.4.2.5 SIMD vector element list It is also possible for registers in a list to have a vector element form, for example LD4 loading one element into each of four registers, in which case the index is appended to the list, as follows: {V4.S - V7.S}3standard disassembly {V4.4S, V5.4S, V6.4S, V7.4S}3alternative with optional number of lanes Список элементов SIMD-векторов Регистры в списке могут содержать внутри себя элементы векторов, например LD4 загружает по одному элименту в каждый из четырех регистров и, в этом случае, индекс добавляется к списку следующем образом: {V4.S - V7.S}3 стандарт для дизасемблера {V4.4S, V5.4S, V6.4S, V7.4S}3 альтернатива с опциональным номером для рядов 4.5 Load/Store Addressing Modes Load/store addressing modes in the A64 instruction set broadly follow T32, using a 64-bit base address from a general register Xn (n=0-30) or the current stack pointer SP, with an immediate or register offset. The complete set of addressing modes is as follows. Some types of load or store instruction may support only a subset of these, and the supported modes are listed in the detailed instruction descriptions below. Режимы адресации для Load/Store Режимы адресации для Load/Store в наборе инструкций A64 в целом схожи с T32, но использует 64-х битные базовые адреса для регистров общего назначения Xn (n=0..30) и текущей позиции в стеке SP, с непосредственно заданным или переданным в регистре смещением. Все возможные режим адресации приведены ниже. Некоторые типы Load/Store могут принимать ограниченное число режимов, что отражено в детальном описании данных инструкций. Base plus offset addressing means that the address is the value in the 64-bit register base plus an offset. Pre-indexed addressing means that the address is the value in the 64-bit register base plus offset, then the address is written back to base. Post-indexed addressing means that the address is the value in the 64-bit register base, then address plus offset is written back to base. Literal addressing meads that the address is the value in the 64-bit program counter PC plus a 19-bit signed word offset, i.e. a word-aligned address within ±1MiB of PC. Only available for loads of 32 bits or larger and prefetch instructions: PC is not usable in other addressing modes. The syntax for label is described in section 5 below. An immediate offset may be unsigned or signed (two’s complement), and unscaled or scaled, depending on the type of load/store instruction. When scaled it is encoded as a multiple of the transfer size, but the assembly language always uses a byte offset with the assembler/disassembler converting as necessary. The usable byte offsets therefore depend on the type of load/store instruction and the transfer size. *Адресация по базе со смещением означает, что адрес складывается из 64-х битного значения в регистре-безе и смещения. *Адресация с преиндексацией - адрес складывается из 64-х битного значения в регистре-базе и смещения, после чего полученое значение записывается обратно в регистр базу. *Адресация с постиндексацией - адресом служет 64-х битное значения в регистре-базе, но после завершения операции его сумма со смещением записывается в регистр базу. *Адресация с литералом - адресом служит сумма 64-х битного програмного счетчика PC и смещения (19-битного слово со знаком). Полученый адрес выровнен по слову в диапазоне ±1MiB от PC. Адресация с литералом только для загрузки данных размером от 32-х бит и инструкций предвыборки, т.к. PC нельзя использовать в других режимах адресации. Синтаксис меток описывается далее в разделе 5. *Непосредственное смещение может быть без знака или со знаком (в формате дополнения до двух), масштабироватся или не масштабироватся в зависимости от типа инструкций load/store. Если непосредственное значение масштабитуется, то оно кодируется в виде нескольких размеров пересылаемых данных, но язык ассемблера всегда использует смещение в байтах, а ассемблер/дизасемблер выполняет необходимую конвертацию. Величина смещения в байтах, пригодного для использования, зависит от типа инструкций load/store и размера пересылаемых данных. A register offset means that offset is the value in 64-bit general register Xm, optionally scaled by the transfer size (in bytes) if so indicated by “,LSL #imm”, where imm=log2(size). An extended register offset means that offset is the value in 32-bit general register Wm, sign or zero extended to 64 bits, then scaled by the transfer size if so indicated by “#imm”, where imm=log2(size). An assembler must accept Wm or Xm as an extended register offset, but Wm is preferred for disassembly. The pre/post-indexed by register offset modes are not generally available, except that post-indexed mode may be used with the Advanced SIMD load/store structure instructions in section 5.8.22. There is no subtract or "down" option, so generating an address lower than the value in the base register requires a negative signed immediate offset or a register offset holding a negative value. When base is SP the current stack pointer must initially be quadword (16 byte) aligned – with misalignment causing a stack alignment fault. The offset does not have to be a multiple of 16 bytes unless so required by the specific load/store instruction. SP may never be used as a register offset. *Передача смещения в регистре, предусматривает хранение в 64-х битном регистре общего назначения Xm, с опциональным масштабированием по размеру пересылаемых данных (в байтах). Масштабирование задается в формате “,LSL #imm”, где imm = log2(size). *Передача расширенного смещения в регистре предполагает хранение в 32-х битном регистре общего назначения Wm и использование оставшейся части 64-х битного пространства для хранения знака или дополнения нулями при масштабировании по размеру передаваемых данных, если таковое задано опцией “#imm”, где imm = log2(size).Ассемблер должен воспринимать и Wm, и Xm как расширенное смещение, однако Wm - предпочтительнее для дизасемблера. *Преиндексация и постиндексация в общем случае не доступны в режиме передачи смещения в регистре. Исключение составляет режим с постиндексацией, который можно использовать в структуре инструкций load/store Расширеного SIMD (см. гл. 5.8.22). *Не существует опции "down" или опции, отвечающей за вычитание. Таким образом, чтобы получить адрес меньше, чем тот, что находится в базовом регистре, необходимо отрицательное смещение заданное непосредственно или переданное в регистре. *Если в качестве базы используется SP - текущая позиция в стеке, то она должна быть предварительно выравнена по границе блока в 16 байт (quadword). Если этого не сделать, то возникнет ошибка выравнивания стека (stack alignment fault). В остальных случаях, если этого не требует форма специальных инструкций load/store, смещение не должно быть кратно 16 байтам. Возможно вам ни когда не придется пользоваться SP, как регистром, содержащим смещение. 4.5.1 Address Computation Apart from pre/post-indexed forms, any addressing mode may be computed and written to a general register or (in most cases) to the current stack pointer using general-purpose arithmetic instructions, as follows: Вычисление адреса Кроме режимов с преиндексацией и постиндексацией, любой результат вычисления адреса может быть записан в регистр общего назначения или (в большинстве случаев) в текущую позицию в стеке с помощью арифметических инструкций общего назначения: Notes: To calculate a base plus immediate offset the ADD (immediate) instructions defined in §5.4.1 accept an unsigned 12-bit immediate, with optional left shift by 12. This means that a single ADD instruction cannot support the full range of byte offsets available to a single register load/store with scaled 12-bit immediate offset. For example a quadword LDR effectively has a 16-bit byte offset. To calculate an address where the byte offset requires more than 12 bits it will be necessary to use two ADD instructions, for example: ADD Xd, base, #(imm & 0xfff) ADD Xd, Xd, #(imm >> 12), LSL #12 To calculate a base plus extended register offset the ADD (extending register) instructions defined in §5.5.2 provide a superset of the load/store addressing mode, since they also support sign or zero- extension of a byte or halfword value, with any shift amount between 0 and 4, for example: ADD Xd, base, Wm, SXTW #3 // Xd = base+(SignExtend(Wm) LSL 3) ADD Xd, base, Wm, UXTH #4 // Xd = base+(ZeroExtend(Wm<15:0>) LSL 4) Замечания: *Инструкция ADD (с непосредственным операндом), описанная в гл. 5.4.1, используется для сложения базы и непосредственного смещения с опциональным сдвигом на 12 и принимает при этом 12-битное непосредственное значение без знака. Это означает, что одна инструкция ADD не может поддерживать весь доступный спектр смещений, доступный операциям load/store для отдельных регистров, принимающим 12-ти битное непосредственное смещение с масштабированием. Например 16-байтной (quadword) LDR можно задать эффективное смешение измеряемое в байтах внутри 16-ти битной переменной. Если для вычисления адреса требуется смещение в байтах, которое нельзя передать в 12-ти битах, то следует использовать две инструкции ADD. Например: ADD Xd, base, #(imm & 0xfff) ADD Xd, Xd, #(imm >> 12), LSL #12 *Инструкция ADD (с расширенным регистром), описанная в гл. 5.2.2, используется для сложения базы и смещения переданного в расширенном регистре. При этом можно использовать больше форм адресации, чем доступны для load/store, т.к. появляется возможность указать знак, дополнить нулями байт и слово, а так же сдвиг на кличество бит от 0 до 4. Например: ADD Xd, base, Wm, SXTW #3 // Xd = base+(SignExtend(Wm) LSL 3) ADD Xd, base, Wm, UXTH #4 // Xd = base+(ZeroExtend(Wm<15:0>) LSL 4) If the same extended register offset is used by more than one load/store instruction then it may –depending on the processor implementation – be more efficient to calculate the zero/sign-extended and scaled intermediate result just once and then reuse it as a simple register offset. The “extend-and-scale” calculation may be performed using the SBFIZ and UBFIZ bitfield instructions defined in §5.4.5, for example: SBFIZ Xd, Xm, #3, #32 // Xd = “Wm, SXTW #3” UBFIZ Xd, Xm, #4, #16 // Xd = “Wm, UXTH #4” *Если один и тот же расширенный регистр используется больше чем одной инструкцией load/store, то он (в зависимости от реализации процессора) может быть использован более эффективно, за счет однократного вычисления расширенного нулями или знаком, а также масштабированного промежуточного результата и последующего использования данного значения в качестве смещения хранящегося в регистре. Вычисления класса "расширение-и-масштабирование" (“extend-and-scale”) могут быть реализованы с помощью инструкций SBFIZ и UBFIZ оперирующих с битами (см. гл. 5.4.5). Например: SBFIZ Xd, Xm, #3, #32 // Xd = “Wm, SXTW #3” UBFIZ Xd, Xm, #4, #16 // Xd = “Wm, UXTH #4”